package org.java.base.select;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * Java NIO 的select是一个组件，它可以检查一个或多个Java NIO通道实例，并确定哪些通道已经准备好了，例如读取或写入。
 * 通过这种方式，单个线程可以管理多个通道，从而可以管理多个网络连接。
 * 每个线程也会占用操作系统中的一些资源(内存)。因此，使用的线程越少越好。
 * 使用Selector 的步骤：
 * 1.创建Selector  Selector selector = Selector.open();
 * <p>
 * 2.注册Channel   channel.configureBlocking(false);  (必须非阻塞)
 * SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
 * 3.第三个参数   意思是你想在channel收听什么事件:
 * Connect
 * Accept
 * Read
 * Write
 */
public class SelectDemo {

    public static void main(String[] args) throws IOException{
        SelectDemo selectDemo = new SelectDemo();
        selectDemo.SelectorExample();
    }

    public void SelectorExample() throws IOException {
        Selector selector = Selector.open();

        SocketChannel channel = SocketChannel.open();
        channel.connect(new InetSocketAddress("http://jenkov.com", 80));
        channel.configureBlocking(false);

        SelectionKey keys = channel.register(selector, SelectionKey.OP_READ);


        while (true) {

            int readyChannels = selector.selectNow();

            if (readyChannels == 0) continue;


            Set<SelectionKey> selectedKeys = selector.selectedKeys();

            Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

            while (keyIterator.hasNext()) {

                SelectionKey key = keyIterator.next();

                if (key.isAcceptable()) {
                    // a connection was accepted by a ServerSocketChannelExample.

                } else if (key.isConnectable()) {
                    // a connection was established with a remote server.

                } else if (key.isReadable()) {
                    // a channel is ready for reading

                } else if (key.isWritable()) {
                    // a channel is ready for writing
                }

                keyIterator.remove();
            }
        }
    }
}
